package com.cweb.admin.serivce.authority;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.cweb.admin.model.sys.sys_role_info.service.SysRoleInfoService;
import com.cweb.framework.pojo.CustomException;
import com.cweb.framework.util.ErrorEnum;
import com.cweb.framework.util.MyConstant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;

@Service
public class AuthorityJWTService implements Authority {
    @Autowired
    private SysRoleInfoService roleInfoService;
    @Autowired
    private UserLoginService userLoginService;

    /**
     * 登录，生成token
     */
    @Override
    public UserLoginToken login(UserLoginToken loginToken) {
        // 失效时间
        Date expiresAt = DateTime.now().offset(DateField.MINUTE, MyConstant.Authority.CONFIG_USER_TOKEN_VALID);
        // 返回值生成UserLoginToken
        loginToken.setExpiresAt(expiresAt);
        // 使用JWT生成token
        String token = JWT.create()
                .withAudience(String.valueOf(loginToken.getId()))
                .withClaim("id", loginToken.getId())
                .withClaim("name", loginToken.getName())
                .withClaim("type", loginToken.getType())
                .withClaim("linkId", loginToken.getLinkId())
                .withClaim("role", null == loginToken.getRole() ? null : String.join(",", loginToken.getRole()))
                .withExpiresAt(expiresAt)
                .sign(Algorithm.HMAC256(MyConstant.Authority.CONFIG_USER_TOKEN_SIGN_KEY));
        loginToken.setToken(token);
        return loginToken;
    }

    /**
     * 登出
     */
    @Override
    public boolean logout(HttpServletRequest request) {
        return false;
    }

    /**
     * 检测登录token
     */
    @Override
    public UserLoginToken checkAuthority(HttpServletRequest request) throws CustomException {
        // 取得请求路径
        String url = request.getRequestURI();
        // 取得登录token
        String token = request.getHeader(HttpHeaders.AUTHORIZATION);
        // 特殊的get请求判断
        if (null == token && HttpMethod.GET.name().equals(request.getMethod()) && StrUtil.isNotBlank(request.getParameter(HttpHeaders.AUTHORIZATION))) {
            token = request.getParameter(HttpHeaders.AUTHORIZATION);
        }
        if (null == token) {
            throw new CustomException(ErrorEnum.USER_LOGIN_TOKEN_NULL);
        }
        // token验证
        DecodedJWT jwt = null;
        try {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(MyConstant.Authority.CONFIG_USER_TOKEN_SIGN_KEY)).build();
            jwt = verifier.verify(token);
        } catch (JWTVerificationException e) {
            throw new CustomException(ErrorEnum.USER_LOGIN_TOKEN_NULL);
        }
        // 解码
        UserLoginToken loginToken = new UserLoginToken();
        loginToken.setId(jwt.getClaim("id").asLong());
        loginToken.setName(jwt.getClaim("name").asString());
        loginToken.setType(jwt.getClaim("type").asString());
        loginToken.setLinkId(jwt.getClaim("linkId").asLong());
        if (!jwt.getClaim("role").isNull() && !"".equals(jwt.getClaim("role").asString())) {
            loginToken.setRole(jwt.getClaim("role").asString().split(","));
        }

        // 线程保存用户信息
        userLoginService.setCurLoginToken(loginToken);

        // 用户是超级用户时，不进行用户角色权限验证
        if ("super".equals(loginToken.getType())) {
            return loginToken;
        }
        // 用户角色权限验证
        // todo:
//        if (!checkMappingForRole(url, loginToken.getRole())) {
//            throw new CustomException(ErrorEnum.USER_LOGIN_TOKEN_NO_AUTHORITY);
//        }
        return loginToken;
    }

    /**
     * 判断角色是否拥有对应接口的权限
     */
    private boolean checkMappingForRole(String mapping, String[] roleIds) {
        if (null == roleIds) {
            return false;
        }
        for (String roleId : roleIds) {
            // 取得此角色的权限
            List<String> mappings = roleInfoService.selectMappingByRole(Long.valueOf(roleId));
            if (mappings.indexOf(mapping) != -1) {
                return true;
            }
        }
        return false;
    }
}
